package socket

import (
	"fmt"
	"github.com/go-vgo/robotgo"
	"github.com/gorilla/websocket"
	"github.com/kbinani/screenshot"
	log "github.com/sirupsen/logrus"
	"sailing.cn/v2/convert"
)

const (
	KEYBOARD_EVENT   = "keyboard-event"
	MOUSE_EVENT      = "mouse-event"
	RESOLUTION_RATIO = "resolution-ratio"
	SCREEN_INFO      = "screen-info"
)

type WebSocketHandler struct{}

func AnyToModel[T interface{}](source interface{}) *T {
	bytes := convert.ToBytes(source)
	result := convert.ToModel[T](bytes)
	return result
}

func (handler *WebSocketHandler) handle(client *Client, message []byte) {
	msg := convert.ToModel[WebSocketMessage](message)
	switch msg.Type {
	case RESOLUTION_RATIO:
		{
			temp := convert.ToBytes(msg.Data)
			data := convert.ToModel[ResolutionRatio](temp)
			width = data.Width
			height = data.Height
			quality = data.Quality
			break
		}
	case KEYBOARD_EVENT:
		{
			temp := convert.ToBytes(msg.Data)
			data := convert.ToModel[KeyboardEvent](temp)
			args := make([]interface{}, 0)
			if data.AltKey {
				args = append(args, robotgo.Alt)
			}
			if data.ShiftKey {
				args = append(args, robotgo.Shift)
			}
			if data.CtrlKey {
				args = append(args, robotgo.Ctrl)
			}
			robotgo.KeyTap(data.Key, args...)
			break
		}
	case MOUSE_EVENT:
		{
			//fmt.Println("收到鼠标事件", msg.Data)
			temp := convert.ToBytes(msg.Data)
			data := convert.ToModel[MouseEvent](temp)
			data.handle()
			break
		}
	case SCREEN_INFO:
		{
			result := &DisplayInfo{ScreenList: make([]*DisplayScreen, 0)}
			for i := 0; i < screenshot.NumActiveDisplays(); i++ {
				bounds := screenshot.GetDisplayBounds(i)
				result.ScreenList = append(result.ScreenList, &DisplayScreen{
					ResolutionRatio: ResolutionRatio{
						Width:  bounds.Max.X,
						Height: bounds.Max.X,
					}})
			}
			msg.Data = result
			_bytes := convert.ToBytes(msg)
			if err := client.conn.WriteMessage(websocket.TextMessage, _bytes); err != nil {
				fmt.Println("发生错误", err.Error())
			}

		}
	}
}

func (m *MouseEvent) handle() {
	switch m.Type {
	case "mousemove":
		{
			robotgo.Move(m.OffsetX, m.OffsetY)
			break
		}
	case "mousedown":
		{
			key := m.GetMouseKey()
			robotgo.MouseDown(key)
		}
	case "mouseup":
		{
			key := m.GetMouseKey()
			robotgo.MouseUp(key)
		}
	default:
		log.Println("鼠标事件", m.Type)
	}
}
func (m *MouseEvent) GetMouseKey() string {
	for k, v := range robotgo.MouseMap {
		if v == m.Button+1 {
			return k
		}
	}
	return ""
}

type MouseEvent struct {
	Type    string `json:"type"`
	OffsetX int    `json:"offsetX"`
	OffsetY int    `json:"offsetY"`
	Button  uint16 `json:"button"`
}

type KeyboardEvent struct {
	Type     string `json:"type"`
	Key      string `json:"key"`
	Code     string `json:"code"`
	Location int    `json:"location"`
	CtrlKey  bool   `json:"ctrlKey"`
	AltKey   bool   `json:"altKey"`
	ShiftKey bool   `json:"shiftKey"`
}

type ResolutionRatio struct {
	Width   int `json:"width"`
	Height  int `json:"height"`
	Quality int `json:"quality"`
}

type DisplayInfo struct {
	ScreenList []*DisplayScreen `json:"screen_list"`
}

type DisplayScreen struct {
	ResolutionRatio ResolutionRatio `json:"resolution_ratio"`
}
